#include <huniplacer_3d/CrateModel.h>

#include <xml_io/xml.h>

#include <GL/gl.h>
#include <GL/freeglut.h>

#include <huniplacer_3d/Render.h>
#include <huniplacer_3d/CrateContent.h>
#include <huniplacer_3d/huniplacer_3d.h>
#include <huniplacer_3d/Picking.h>

#include <string>

#include <iostream>

CrateModel::CrateModel(
		RobotModel* model,
		std::string n,
		point3 size,
		point3 location,
		double rotation) :
		Picking(n), m_Model(model), m_Size(size), m_Location(location), m_Rotation(rotation), nr_balls_width(0), nr_balls_depth(0) {
		
	m_Model->addCrate(this);
	
	double distance_to_side = 0, distance_to_next = 0, radius_content = 0;
	
	//TODO: change this shit
   utility_xml::crate_data(getHuniplacerData()->modeldata.crate_xml, 
   								name, 
   								&m_Size.x, 
   								&m_Size.z, 
   								&m_Size.y, 
   								&nr_balls_width, 
   								&nr_balls_depth, 
   								&distance_to_side, 
   								&distance_to_next, 
   								&radius_content, 
   								NULL);
   								
   std::cout << "name: " << name << "width: " << nr_balls_width << ":" << nr_balls_depth << std::endl;

	content = new CrateContent*[nr_balls_depth*nr_balls_width];
	
	float x = -m_Size.x/2 + distance_to_side;
	for (int i = 0; i < nr_balls_depth; i++) {
		x+= distance_to_next + radius_content;
		
		float z = -m_Size.z/2 + distance_to_side;
		for (int j = 0; j < nr_balls_width; j++) {
			z+= distance_to_next + radius_content;
		
			content[j + nr_balls_width*i] = new CrateContent(this, j + nr_balls_width*i, point3(x, 0.5, z), point3(radius_content*2, m_Size.y, radius_content*2), 1, 0, 0);
		
			z+= radius_content;
		}
		
		x+= radius_content;
	}
	
	/*beat_color = new float*[nr_balls_depth*nr_balls_width];
	beat_detected = new float[nr_balls_depth*nr_balls_width];
	
	for (int i = 0; i < nr_balls_depth*nr_balls_width; i++) {
		beat_color[i] = new float[3];
		
		beat_color[i][0] = 1.0;
		beat_color[i][1] = 0.0;
		beat_color[i][2] = 0.0;
		
		beat_detected[i] = 0;
	}
	
	beat_types = 1;
	*/
	//std::cout << "crate name: " << name << std::endl;
}

CrateModel::~CrateModel() {
	m_Model->removeCrate(this);
}

void CrateModel::draw() {	
	glPushMatrix();
	set_color4f(0.5, 0.5, 0.5, m_Alpha); /* !!!This is not an OpenGL function, this function is located in the base class: Picking!!! */
	glTranslatef(	m_Location.x, 
						m_Location.y,
						m_Location.z);
	glRotatef(huniplacer::utils::deg(m_Rotation), 0, 1, 0);
	
	glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
	glGetDoublev(GL_PROJECTION_MATRIX, projection);
	glGetIntegerv(GL_VIEWPORT, viewport);
	
	drawCube(0, 0, 0, m_Size.x, m_Size.y,
			m_Size.z);
	
	if (getHuniplacerData()->modeldata.draw_beads) {
		for (int i = 0; i < nr_balls_depth * nr_balls_width; i++) {
			content[i]->draw();
		}
	}
	
	glPopMatrix();
}

void CrateModel::drawCube(float x, float y, float z, float width, float height, float depth) {
	glBegin(GL_QUADS); // Draw A Quad

	glVertex3f(x + (0.5f * width), y + (0.5f * height), z + (-0.5f * depth)); // Top Right Of The Quad (Top)
	glVertex3f(x + (-0.5f * width), y + (0.5f * height), z + (-0.5f * depth)); // Top Left Of The Quad (Top)
	glVertex3f(x + (-0.5f * width), y + (0.5f * height), z + (0.5f * depth)); // Bottom Left Of The Quad (Top)
	glVertex3f(x + (0.5f * width), y + (0.5f * height), z + (0.5f * depth)); // Bottom Right Of The Quad (Top)

	glVertex3f(x + (0.5f * width), y + (-0.5f * height), z + (0.5f * depth)); // Top Right Of The Quad (Bottom)
	glVertex3f(x + (-0.5f * width), y + (-0.5f * height), z + (0.5f * depth)); // Top Left Of The Quad (Bottom)
	glVertex3f(x + (-0.5f * width), y + (-0.5f * height), z + (-0.5f * depth)); // Bottom Left Of The Quad (Bottom)
	glVertex3f(x + (0.5f * width), y + (-0.5f * height), z + (-0.5f * depth)); // Bottom Right Of The Quad (Bottom)

	glVertex3f(x + (0.5f * width), y + (0.5f * height), z + (0.5f * depth)); // Top Right Of The Quad (Front)
	glVertex3f(x + (-0.5f * width), y + (0.5f * height), z + (0.5f * depth)); // Top Left Of The Quad (Front)
	glVertex3f(x + (-0.5f * width), y + (-0.5f * height), z + (0.5f * depth)); // Bottom Left Of The Quad (Front)
	glVertex3f(x + (0.5f * width), y + (-0.5f * height), z + (0.5f * depth)); // Bottom Right Of The Quad (Front)

	glVertex3f(x + (0.5f * width), y + (-0.5f * height), z + (-0.5f * depth)); // Top Right Of The Quad (Back)
	glVertex3f(x + (-0.5f * width), y + (-0.5f * height), z + (-0.5f * depth)); // Top Left Of The Quad (Back)
	glVertex3f(x + (-0.5f * width), y + (0.5f * height), z + (-0.5f * depth)); // Bottom Left Of The Quad (Back)
	glVertex3f(x + (0.5f * width), y + (0.5f * height), z + (-0.5f * depth)); // Bottom Right Of The Quad (Back)

	glVertex3f(x + (-0.5f * width), y + (0.5f * height), z + (0.5f * depth)); // Top Right Of The Quad (Left)
	glVertex3f(x + (-0.5f * width), y + (0.5f * height), z + (-0.5f * depth)); // Top Left Of The Quad (Left)
	glVertex3f(x + (-0.5f * width), y + (-0.5f * height), z + (-0.5f * depth)); // Bottom Left Of The Quad (Left)
	glVertex3f(x + (-0.5f * width), y + (-0.5f * height), z + (0.5f * depth)); // Bottom Right Of The Quad (Left)

	glVertex3f(x + (0.5f * width), y + (0.5f * height), z + (-0.5f * depth)); // Top Right Of The Quad (Right)
	glVertex3f(x + (0.5f * width), y + (0.5f * height), z + (0.5f * depth)); // Top Left Of The Quad (Right)
	glVertex3f(x + (0.5f * width), y + (-0.5f * height), z + (0.5f * depth)); // Bottom Left Of The Quad (Right)
	glVertex3f(x + (0.5f * width), y + (-0.5f * height), z + (-0.5f * depth)); // Bottom Right Of The Quad (Right)
	glEnd(); // Done Drawing The Quad
}

double CrateModel::getRotation(){
	return m_Rotation;
}

void CrateModel::set_content_color(int content_index, float r, float g, float b) {
	content[content_index]->change_color(r, g, b);
}

int CrateModel::getNrBallsWidth(){
	return nr_balls_width;
}

int CrateModel::getNrBallsDepth(){
	return nr_balls_depth;
}

void CrateModel::setNrBallsWidth(int rows){
	nr_balls_width = rows;
}

void CrateModel::setNrBallsDepth(int cols){
	nr_balls_depth = cols;
}

point3 CrateModel::getLocation(){
	return m_Location;
}

point3 CrateModel::getSize(){
	return m_Size;
}

void CrateModel::setLocation(point3& loc){
	m_Location = loc;
}

void CrateModel::setRotation(double rot){
	m_Rotation = rot;
}

void CrateModel::setAlpha(float alpha){
	m_Alpha = alpha;
}

float CrateModel::getAlpha(){
	return m_Alpha;
}
